/**
 * Actor's the make up the game
 */

package edu.gatech.spacetraderteam3.model;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import edu.gatech.spacetraderteam3.debug.Debug;

/**
 * Actor class that has ship and inventory
 * 
 * @author randal
 * @version 0.1
 */
public class Actor implements Serializable {

    /**
     * The serial Version UID for this Actor
     */
    private static final long serialVersionUID = 8566644566280396593L;

    /**
     * The name of this Actor
     */
    private String name;

    /**
     * This Actor's Faction (allegience)
     */
    private Faction faction;

    /**
     * The Actor's ship
     */
    protected Ship ship;

    /**
     * The Actor's inventory (goods, items, cargo, etc)
     */
    protected Inventory inventory;

    /**
     * A Random Numeric Constant
     */
    private static final Random RAND = new Random();

    /**
     * Constructor for the Actor class. Gives him a name, a ship (if he has one), a
     * faction and an inventory
     * 
     * @param name
     *            The actor's name
     * @param faction
     *            The actor's alliance
     * @param ship
     *            The actor's ship
     */
    public Actor(String name, Faction faction, Ship ship) {
        this.name = name;
        this.faction = faction;
        this.ship = ship;
        this.inventory = new Inventory();
    }

    /**
     * Constructor for the actor class that gives a default name
     * 
     * @param faction
     *            The actor's alliance
     * @param ship
     *            The actor's ship (if applicable)
     */
    public Actor(Faction faction, Ship ship) {
        // make something that generates names. Could be funny
        this("PINGAS", faction, ship);
    }

    /**
     * Gets the name of the actor
     * 
     * @return the name of the actor
     */
    public String getName() {
        return name;
    }

    /**
     * Gets the actor's alliance
     * 
     * @return the actor's alliance
     */
    public Faction getFaction() {
        return faction;
    }

    /**
     * Gets the actor's ship
     * 
     * @return the actor's ship
     */
    public Ship getShip() {
        return ship;
    }

    /**
     * Removes a resource from the thing with n count in a very dramatic manner
     * 
     * @param r
     *            Resource to remove
     * @param n
     *            How much to remove
     * @return Whether it was removed.
     */
    public boolean removeResource(Resource r, int n) {
        Debug.write("Resource: " + r + " Number: " + n + " Inventory: "
                            + inventory.getResource(r) + " Ship: "
                            + ship.getCurrentWeight(), Debug.USER);
        if (this.inventory.removeResource(r, n)) {
            this.ship.removeWeight(r.weight() * n);
            return true;
        }
        return false;
    }

    /**
     * Checks if the actor's inventory can hold a resource
     * 
     * @param res
     *            resource to check
     * @param num
     *            number of said resource
     * @return whether can hold resource.
     */
    public boolean canHold(Resource res, int num) {
        return this.ship.canHold(res, num);
    }

    /**
     * Add's resource to actor's inventory
     * 
     * @param r
     *            Resource to add to inventory
     * @param n
     *            Number for resource to add
     * @return Whether resource was added
     */
    public boolean addResource(Resource r, int n) {
        if (canHold(r, n)) {
            if (inventory.addResource(r, n)) {
                this.ship.addWeight(r.weight() * n);
                return true;
            }
        }
        return false;
    }

    /**
     * Gets the actor's inventory
     * 
     * @return the actor's inventory
     */
    public Inventory getInventory() {
        return inventory;
    }

    /**
     * Gets a string of composed of the actor's name, faction and ship
     * 
     * @return the string
     */
    public String toString() {
        return name + ", " + faction.toString() + ", " + ship.toString();
    }

    /**
     * Gets a map of the resources in an actor's inventory and their corresponding buy
     * prices
     * 
     * @return map of resources to buy prices
     */
    public Map<Resource, Integer> getPrices() {
        final Map<Resource, Integer> prices = new HashMap<Resource, Integer>();
        for (Resource r : Resource.values()) {
            if (inventory.getResource(r) > 0) {
                prices.put(r,
                           r.basePrice()
                                   + (RAND.nextBoolean() ? -1 * r.variance() : r
                                           .variance()));
            }
        }

        return prices;
    }

    /**
     * Gets a map of the items in the actor's inventory and their corresponding sell
     * prices
     * 
     * @return mao of resources to sell prices.
     */
    public Map<Resource, Integer> getSellPrices() {
        final Map<Resource, Integer> prices = new HashMap<Resource, Integer>();
        for (Resource r : Resource.values()) {
            prices.put(r,
                       r.basePrice()
                               + (RAND.nextBoolean() ? -1 * r.variance() : r.variance()));

        }

        return prices;
    }

    /**
     * Generates a random inventory for an actor depending on the Actor's faction
     */
    public void populateInventory() {
        switch (faction) {
            case PIRATE:
                inventory.populate(true);

                break;
            case MERCHANT:
                inventory.populate(false);

                break;
            case POLICE:
                inventory.populate(true);

                break;
            default:
                break;
        }
    }
}
